import json

from django.shortcuts import render
from rest_framework.generics import ListAPIView
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet

from django.db.models import Q
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

from home import models, homeser
import redis

from home.models import PositionType

redis = redis.Redis(host="localhost", port=6379, db=15, decode_responses=True)
# models.py 中添加信号处理（确保数据变更时清除缓存）
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
import redis


# 自定义分页配置类，继承自DRF的PageNumberPagination
class pagination(PageNumberPagination):
    page_size = 10  # 设置默认每页显示的数据条数为10条
    page_size_query_param = 'size'  # 允许客户端通过URL参数'size'自定义每页显示条数


# Create your views here.
# 职位类型视图集，继承ListAPIView用于处理列表查询请求
class PositionTypeViewsSet(ListAPIView):
    queryset = models.PositionType.objects.filter(isdel=False)
    # 指定使用的序列化器：职位类型序列化器
    serializer_class = homeser.PositionTypeSerializer
    # 指定使用的分页类：上面自定义的pagination类
    pagination_class = pagination

    # 重写get_queryset方法，用于根据请求参数动态筛选查询集
    def get_queryset(self):
        # 基础查询集：筛选未删除的职位类型
        queryset = models.PositionType.objects.filter(isdel=False)
        # 从请求查询参数中获取parent_id（父级ID）
        parent_id = self.request.query_params.get('parent_id')
        # 如果存在parent_id参数，则筛选父级ID匹配的记录
        if parent_id:
            queryset = queryset.filter(parent_id=parent_id)
        # 从请求查询参数中获取search（搜索关键词）
        search = self.request.query_params.get('search')
        # 如果存在search参数，则通过Q对象筛选职位类型名称包含关键词的记录（不区分大小写）
        if search:
            queryset = queryset.filter(Q(position_type__icontains=search))
        # 返回按sort字段排序后的查询集
        return queryset.order_by('sort')

    # 重写list方法，实现带缓存的列表查询逻辑
    def list(self, request, *args, **kwargs):
        # 从请求中获取筛选参数parent_id和search
        parent_id = request.query_params.get('parent_id')
        search = request.query_params.get('search')
        # 初始化缓存键的基础部分：职位类型列表的标识
        key_parts = ["position_type_list"]
        # 如果有parent_id参数，将其添加到缓存键部分，区分不同父级的缓存
        if parent_id:
            key_parts.append(f'parent_{parent_id}')
        print(key_parts)  # 打印缓存键部分，用于调试
        # 如果有search参数，将其添加到缓存键部分，区分不同搜索关键词的缓存
        if search:
            key_parts.append(f'search_{search}')
        print(key_parts)  # 打印更新后的缓存键部分，用于调试

        # 将缓存键部分拼接为完整的缓存键（用点分隔）
        cache_key = ".".join(key_parts)
        # 从redis中获取该缓存键对应的缓存数据
        cached_data = redis.get(cache_key)
        # 如果缓存存在
        if cached_data:
            # 将缓存的JSON字符串解析为Python列表
            data_list = json.loads(cached_data)
        # 如果缓存不存在
        else:
            # 调用get_queryset获取筛选后的查询集
            queryset = self.get_queryset()
            # 使用序列化器序列化查询集（many=True表示序列化多条数据）
            serializer = self.get_serializer(queryset, many=True)
            # 获取序列化后的原始数据列表
            data_list = serializer.data
            # 将数据存入redis，设置过期时间300秒（5分钟）
            redis.setex(cache_key, 300, json.dumps(data_list))
        # 实例化分页器
        paginator = self.pagination_class()
        # 对数据列表进行分页处理
        page_data = paginator.paginate_queryset(data_list, request, view=self)
        # 如果分页后有数据
        if page_data:
            # 返回分页后的响应（包含count、next、previous等分页信息）
            return paginator.get_paginated_response(page_data)
        # 如果没有分页数据（如数据量小于一页），直接返回原始数据列表
        return Response(data_list)


# 初始化redis连接：连接本地redis服务，端口6379，数据库15，开启响应解码（自动将bytes转为str）
redis = redis.Redis(host="localhost", port=6379, db=15, decode_responses=True)


# 定义信号接收器：监听PositionType模型的post_save（保存后）和post_delete（删除后）信号
@receiver([post_save, post_delete], sender=PositionType)
def clear_position_type_cache(sender, **kwargs):
    # 当职位类型数据发生变更（新增、修改、删除）时，清除相关缓存
    # 模糊匹配所有以'position_type_list:'开头的缓存键并删除（简单粗暴的缓存清理方式）
    for key in redis.keys('position_type_list:*'):
        redis.delete(key)


# 头部导航视图集，继承ListAPIView用于处理列表查询请求
class headNavigationViewsSet(ListAPIView):
    # 查询集：获取所有头部导航数据
    queryset = models.headNavigation.objects.all()
    # 指定使用的序列化器：头部导航序列化器
    serializer_class = homeser.headNavigationSerializer


